improvement: Add the ability to render Mermaid flowcharts.#175
Merged
Conversation
4dffc97 to
b0e2d1e
Compare
b0e2d1e to
8ade2c4
Compare
Adds `Reactor.Mermaid.to_mermaid/2`.
8ade2c4 to
e9eadf1
Compare
Contributor
Author
|
Here's a more pathological example as requested by @zachdaniel flowchart LR
start{"Start"}
start==>reactor_Neon.Reactor.StartupReactor
subgraph reactor_Neon.Reactor.StartupReactor["Neon.Reactor.StartupReactor"]
direction LR
input_9198890>"Input supervisor"]
step_44774040["secrets(Reactor.Step.Compose)"]
subgraph reactor_66969717["{Neon.Reactor.EnsureAllSecretsReactor, :secrets}"]
direction LR
step_14043928 -->|value|step_33852712
step_33852712[Transform argument path]
step_14043928 -->|value|step_127867733
step_127867733[Transform argument path]
step_14043928 -->|value|step_61719474
step_61719474[Transform argument path]
step_33852712 -->|path|step_52616830
value_72326164{{"`64`"}}
value_72326164 -->|secret_length|step_52616830
value_93482233{{"`\[NeonWeb\.Endpoint, :secret\_key\_base\]`"}}
value_93482233 -->|app_path|step_52616830
step_52616830["phx_secret_key_base(Reactor.Step.Compose)"]
subgraph reactor_124429572["{Neon.Reactor.EnsureSecretReactor, :phx_secret_key_base}"]
direction LR
input_30549490>"Input path"]
input_30349613>"Input secret_length"]
input_27225100>"Input app_path"]
value_neon_core{{"`:neon\_core`"}}
value_neon_core -->|otp_app|step_92232422
input_27225100 -->|path|step_92232422
step_115529526 -->|value|step_92232422
step_92232422["set_secret(Neon.Reactor.Steps.SetAppEnvStep)"]
step_74828596 -->|secret|step_115529526
input_30349613 -->|secret_length|step_115529526
step_115529526["secret_content(Reactor.Step.AnonFn)"]
input_30549490 -->|path|step_74828596
step_74828596["original_content(Reactor.File.Step.ReadFile)"]
step_7420378 -->|value|step_100565385
step_100565385["maybe_write_file(Reactor.Step.Switch)"]
step_100565385_decision@{shape: diamond, label: "Decision for maybe_write_file"}
step_100565385-->step_100565385_decision
step_100565385_decision-->step_96566794
subgraph step_96566794["match branch of maybe_write_file"]
input_30549490 -->|path|step_49914735
step_115529526 -->|content|step_49914735
step_49914735["secret_file(Reactor.File.Step.WriteFile)"]
direction LR
end
step_74828596 -->|original|step_7420378
step_115529526 -->|new|step_7420378
step_7420378["content_changed?(Reactor.Step.AnonFn)"]
return_124429572{"Return"}
step_115529526==>return_124429572
end
step_52616830-->input_27225100
step_52616830-->input_30349613
step_52616830-->input_30549490
return_124429572-->step_52616830
step_127867733 -->|path|step_7866072
value_67142174{{"`16`"}}
value_67142174 -->|secret_length|step_7866072
value_59888801{{"`\[NeonWeb\.Endpoint, :live\_view, :signing\_salt\]`"}}
value_59888801 -->|app_path|step_7866072
step_7866072["phx_live_view_signing_salt(Reactor.Step.Compose)"]
subgraph reactor_71196029["{Neon.Reactor.EnsureSecretReactor, :phx_live_view_signing_salt}"]
direction LR
input_11139820>"Input path"]
input_45448196>"Input secret_length"]
input_112027663>"Input app_path"]
value_neon_core{{"`:neon\_core`"}}
value_neon_core -->|otp_app|step_111503509
input_112027663 -->|path|step_111503509
step_73727431 -->|value|step_111503509
step_111503509["set_secret(Neon.Reactor.Steps.SetAppEnvStep)"]
step_102532192 -->|secret|step_73727431
input_45448196 -->|secret_length|step_73727431
step_73727431["secret_content(Reactor.Step.AnonFn)"]
input_11139820 -->|path|step_102532192
step_102532192["original_content(Reactor.File.Step.ReadFile)"]
step_92208032 -->|value|step_2235755
step_2235755["maybe_write_file(Reactor.Step.Switch)"]
step_2235755_decision@{shape: diamond, label: "Decision for maybe_write_file"}
step_2235755-->step_2235755_decision
step_2235755_decision-->step_33123163
subgraph step_33123163["match branch of maybe_write_file"]
input_11139820 -->|path|step_130111125
step_73727431 -->|content|step_130111125
step_130111125["secret_file(Reactor.File.Step.WriteFile)"]
direction LR
end
step_102532192 -->|original|step_92208032
step_73727431 -->|new|step_92208032
step_92208032["content_changed?(Reactor.Step.AnonFn)"]
return_71196029{"Return"}
step_73727431==>return_71196029
end
step_7866072-->input_112027663
step_7866072-->input_45448196
step_7866072-->input_11139820
return_71196029-->step_7866072
step_61719474 -->|path|step_50144077
value_72326164{{"`64`"}}
value_72326164 -->|secret_length|step_50144077
value_87125564{{"`\[Neon\.Accounts, :token\_signing\_secret\]`"}}
value_87125564 -->|app_path|step_50144077
step_50144077["aa_token_signing_secret(Reactor.Step.Compose)"]
subgraph reactor_59877050["{Neon.Reactor.EnsureSecretReactor, :aa_token_signing_secret}"]
direction LR
input_81702250>"Input path"]
input_127553628>"Input secret_length"]
input_113275556>"Input app_path"]
value_neon_core{{"`:neon\_core`"}}
value_neon_core -->|otp_app|step_101178976
input_113275556 -->|path|step_101178976
step_118903631 -->|value|step_101178976
step_101178976["set_secret(Neon.Reactor.Steps.SetAppEnvStep)"]
step_19143458 -->|secret|step_118903631
input_127553628 -->|secret_length|step_118903631
step_118903631["secret_content(Reactor.Step.AnonFn)"]
input_81702250 -->|path|step_19143458
step_19143458["original_content(Reactor.File.Step.ReadFile)"]
step_42402661 -->|value|step_52346503
step_52346503["maybe_write_file(Reactor.Step.Switch)"]
step_52346503_decision@{shape: diamond, label: "Decision for maybe_write_file"}
step_52346503-->step_52346503_decision
step_52346503_decision-->step_52319625
subgraph step_52319625["match branch of maybe_write_file"]
input_81702250 -->|path|step_32774053
step_118903631 -->|content|step_32774053
step_32774053["secret_file(Reactor.File.Step.WriteFile)"]
direction LR
end
step_19143458 -->|original|step_42402661
step_118903631 -->|new|step_42402661
step_42402661["content_changed?(Reactor.Step.AnonFn)"]
return_59877050{"Return"}
step_118903631==>return_59877050
end
step_50144077-->input_113275556
step_50144077-->input_127553628
step_50144077-->input_81702250
return_59877050-->step_50144077
value_123381424{{"`"config/secrets"`"}}
value_123381424 -->|sub_path|step_14043928
step_14043928["secrets_path(Reactor.Step.Compose)"]
subgraph reactor_105441487["{Neon.Reactor.EnsureStoragePathReactor, :secrets_path}"]
direction LR
input_35399639>"Input sub_path"]
step_65352851 -->|path|step_23566636
step_23566636["mkdir(Reactor.File.Step.MkdirP)"]
input_35399639 -->|sub_path|step_65352851
step_65352851["path(Reactor.Step.AnonFn)"]
return_105441487{"Return"}
step_65352851==>return_105441487
end
step_14043928-->input_35399639
return_105441487-->step_14043928
return_66969717{"Return"}
step_50144077==>return_66969717
end
return_66969717-->step_44774040
input_9198890 -->|supervisor|step_2670933
value_NeonWeb.Endpoint{{"`NeonWeb\.Endpoint`"}}
value_NeonWeb.Endpoint -->|child_spec|step_2670933
step_100673197 -->|_|step_2670933
step_44774040 -->|_|step_2670933
step_2670933["endpoint(Reactor.Process.Step.StartChild)"]
step_120864991 -->|_|step_100673197
step_100673197["settings(Reactor.Step.Compose)"]
subgraph reactor_122041945["{Neon.Reactor.ApplySettingsReactor, :settings}"]
direction LR
step_92922204 -->|value|step_117256111
step_117256111[Transform argument value]
step_101217954 -->|value|step_83362370
step_83362370[Transform argument arguments]
value_vintage_net{{"`:vintage\_net`"}}
value_vintage_net -->|otp_app|step_26270303
value_49508896{{"`\[:regulatory\_domain\]`"}}
value_49508896 -->|path|step_26270303
step_117256111 -->|value|step_26270303
step_26270303["set_wifi_country(Neon.Reactor.Steps.SetAppEnvStep)"]
value_neon_core{{"`:neon\_core`"}}
value_neon_core -->|otp_app|step_126882274
value_133893407{{"`\[:timezone\]`"}}
value_133893407 -->|path|step_126882274
step_92922204 -->|value|step_126882274
step_126882274["set_system_timezone(Neon.Reactor.Steps.SetAppEnvStep)"]
value_39679005{{"`%\{\}`"}}
value_39679005 -->|input|step_125575241
step_125575241["get_settings(Ash.Reactor.ReadOneStep)"]
value_41978982{{"`"/usr/bin/hostname"`"}}
value_41978982 -->|command|step_121158215
step_83362370 -->|arguments|step_121158215
step_44347617 -->|_|step_121158215
step_121158215["set_system_hostname(Neon.Reactor.Steps.RunCommandStep)"]
value_123524932{{"`"config/etc"`"}}
value_123524932 -->|sub_path|step_101217954
step_101217954["etc_path(Reactor.Step.Compose)"]
subgraph reactor_103570142["{Neon.Reactor.EnsureStoragePathReactor, :etc_path}"]
direction LR
input_39732180>"Input sub_path"]
step_113242578 -->|path|step_1594212
step_1594212["mkdir(Reactor.File.Step.MkdirP)"]
input_39732180 -->|sub_path|step_113242578
step_113242578["path(Reactor.Step.AnonFn)"]
return_103570142{"Return"}
step_113242578==>return_103570142
end
step_101217954-->input_39732180
return_103570142-->step_101217954
step_101217954 -->|base|step_108132378
step_108132378["etc_hosts_path(Reactor.Step.AnonFn)"]
step_108132378 -->|path|step_13234098
step_110135308 -->|content|step_13234098
step_13234098["write_etc_hosts(Reactor.File.Step.WriteFile)"]
step_92922204 -->|settings|step_110135308
step_110135308["etc_hosts_content(Reactor.Step.Template)"]
step_101217954 -->|base|step_20541118
step_20541118["etc_hostname_path(Reactor.Step.AnonFn)"]
step_20541118 -->|path|step_44347617
step_46004921 -->|content|step_44347617
step_44347617["write_etc_hostname(Reactor.File.Step.WriteFile)"]
step_92922204 -->|settings|step_46004921
step_46004921["etc_hostname_content(Reactor.Step.Template)"]
step_125575241 -->|settings|step_92922204
step_92922204["settings(Reactor.Step.AnonFn)"]
return_122041945{"Return"}
step_126882274==>return_122041945
end
return_122041945-->step_100673197
step_120864991 -->|_|step_68426946
step_100673197 -->|_|step_68426946
input_9198890 -->|supervisor|step_68426946
value_Oban{{"`Oban`"}}
value_Oban -->|module|step_68426946
step_68426946["oban(Reactor.Step.Compose)"]
subgraph reactor_29023697["{Neon.Reactor.StartObanReactor, :oban}"]
direction LR
input_121044242>"Input supervisor"]
input_99777965>"Input module"]
value_neon_core{{"`:neon\_core`"}}
value_neon_core -->|otp_app|step_130005066
value_67693049{{"`\[Oban\]`"}}
value_67693049 -->|path|step_130005066
step_130005066["oban_config(Neon.Reactor.Steps.GetAppEnvStep)"]
value_neon_core{{"`:neon\_core`"}}
value_neon_core -->|otp_app|step_64783539
value_59181804{{"`\[:ash\_domains\]`"}}
value_59181804 -->|path|step_64783539
step_64783539["all_domains(Neon.Reactor.Steps.GetAppEnvStep)"]
input_121044242 -->|supervisor|step_80577418
step_127596499 -->|child_spec|step_80577418
step_80577418["oban(Reactor.Process.Step.StartChild)"]
input_99777965 -->|module|step_127596499
step_64783539 -->|all_domains|step_127596499
step_130005066 -->|oban_config|step_127596499
step_127596499["child_spec(Reactor.Step.AnonFn)"]
return_29023697{"Return"}
step_80577418==>return_29023697
end
step_68426946-->input_99777965
step_68426946-->input_121044242
return_29023697-->step_68426946
input_9198890 -->|supervisor|step_120864991
step_120864991["repos(Reactor.Step.Compose)"]
subgraph reactor_133882914["{Neon.Reactor.StartAllReposReactor, :repos}"]
direction LR
input_15973844>"Input supervisor"]
step_89289127 -->|source|step_58628162
step_58628162["migrate_and_start_all_repos(Reactor.Step.Map)"]
subgraph reactor_83839479["{Reactor.Step.Map.Mermaid, :migrate_and_start_all_repos}"]
direction LR
input_36536047>"Input source"]
input_119846339 -->|supervisor|step_74432928
input_36536047 -->|child_spec|step_74432928
step_84659762 -->|_|step_74432928
step_74432928["repo(Reactor.Process.Step.StartChild)"]
input_36536047 -->|repo|step_84659762
step_84659762["migrate(Reactor.Step.AnonFn)"]
return_83839479{"Return"}
step_74432928==>return_83839479
end
step_58628162-->input_36536047
return_83839479-->step_58628162
value_neon_core{{"`:neon\_core`"}}
value_neon_core -->|otp_app|step_89289127
value_38559143{{"`\[:ecto\_repos\]`"}}
value_38559143 -->|path|step_89289127
step_89289127["all_repos(Neon.Reactor.Steps.GetAppEnvStep)"]
return_133882914{"Return"}
step_89289127==>return_133882914
end
step_120864991-->input_15973844
return_133882914-->step_120864991
input_9198890 -->|supervisor|step_125716691
value_Neon.Services.Supervisor{{"`Neon\.Services\.Supervisor`"}}
value_Neon.Services.Supervisor -->|child_spec|step_125716691
step_100673197 -->|_|step_125716691
step_125716691["services(Reactor.Process.Step.StartChild)"]
return_Neon.Reactor.StartupReactor{"Return"}
step_68426946==>return_Neon.Reactor.StartupReactor
end
|
zachdaniel
approved these changes
Feb 28, 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi folks 👋
This PR adds the ability to convert Reactors into Mermaid. It's not particularly pretty yet, but it works well enough to ship it as a first version and can be improved if required.
flowchart LR start{"Start"} start==>reactor_Reactor.MermaidTest.BasicReactor subgraph reactor_Reactor.MermaidTest.BasicReactor["Reactor.MermaidTest.BasicReactor"] direction LR input_105483575>"Input whom"] input_105483575 -->|whom|step_19254403 step_19254403["greet(Example.Step.Greeter)"] return_Reactor.MermaidTest.BasicReactor{"Return"} step_19254403==>return_Reactor.MermaidTest.BasicReactor end